package agent

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/fatih/color"
	"github.com/sashabaranov/go-openai"
)

// Engine 负责执行ReAct循环
type Engine struct {
	agent               *ReActAgent
	prompt              *PromptBuilder
	crossSessionHistory []openai.ChatCompletionMessage // 跨会话真实对话历史
	maxHistoryMessages  int                            // 最大保留历史消息数量
}

// NewEngine 创建新的ReAct执行引擎
func NewEngine(agent *ReActAgent) (*Engine, error) {
	promptBuilder, err := NewPromptBuilder(agent)
	if err != nil {
		return nil, fmt.Errorf("创建提示词构建器失败: %v", err)
	}

	return &Engine{
		agent:               agent,
		prompt:              promptBuilder,
		crossSessionHistory: make([]openai.ChatCompletionMessage, 0),
		maxHistoryMessages:  10, // 最多保留最近10条历史消息
	}, nil
}

// addCrossSessionHistory 添加跨会话的真实对话历史
func (e *Engine) addCrossSessionHistory(session *ReActSession) {
	if len(e.crossSessionHistory) == 0 {
		return
	}

	// 直接添加真实的历史消息
	for _, msg := range e.crossSessionHistory {
		session.AddMessage(msg.Role, msg.Content)
	}
}

// saveSessionHistory 保存会话的真实对话历史到跨会话记忆
func (e *Engine) saveSessionHistory(session *ReActSession) {
	// 保存真实的对话消息
	for _, msg := range session.GetMessages() {
		// 仅保存user和assistant消息，跳过system消息
		if msg.Role == openai.ChatMessageRoleUser || msg.Role == openai.ChatMessageRoleAssistant {
			e.crossSessionHistory = append(e.crossSessionHistory, msg)
		}
	}

	// 限制历史消息数量，保留最近的对话
	if len(e.crossSessionHistory) > e.maxHistoryMessages {
		// 保留最近的消息
		keepCount := e.maxHistoryMessages
		e.crossSessionHistory = e.crossSessionHistory[len(e.crossSessionHistory)-keepCount:]
	}

}

// getFullMessages 获取完整的messages数组，为AI推理添加必要的上下文
func (e *Engine) getFullMessages(session *ReActSession) []openai.ChatCompletionMessage {
	// 获取基础会话消息
	messages := session.GetMessages()

	//如果是ReAct循环中（有执行历史），需要为AI添加状态上下文，但不保存到会话历史
	if e.agent.GetCurrentIteration() > 1 && len(session.GetSteps()) > 0 {
		// 构建执行状态摘要（仅用于AI推理，不保存到历史）
		historyText := e.prompt.BuildHistoryText(session)
		contextMsg := fmt.Sprintf("%s\n基于以上执行历史，请决定下一步该做什么。\n\n**重要格式提醒:**\n- 必须用markdown代码块包裹JSON，格式：```json ... ```\n- JSON内容必须是有效的对象格式\n- 不要包含反引号在JSON内容中\n\n注意：\n- 如果之前的行动失败了，请分析失败原因并调整策略\n- 如果任务已经完成，请返回completed类型的响应\n- 如果需要继续执行，请选择适当的工具继续任务", historyText)

		// 创建临时消息（不保存到session，只用于当前API调用）
		tempMessages := make([]openai.ChatCompletionMessage, len(messages))
		copy(tempMessages, messages)
		tempMessages = append(tempMessages, openai.ChatCompletionMessage{
			Role:    openai.ChatMessageRoleAssistant,
			Content: contextMsg,
		})
		return tempMessages
	}

	return messages
}

// ClearHistory 清除历史（用于用户请求或内存管理）
func (e *Engine) ClearHistory() {
	e.crossSessionHistory = make([]openai.ChatCompletionMessage, 0)
	fmt.Println("[INFO] 所有历史记录已清除")
}

// ProcessGoal 处理用户目标，实现ReAct模式
func (e *Engine) ProcessGoal(ctx context.Context, goal string) error {
	// 创建新会话，但保留历史消息
	session := NewSession(goal)
	e.agent.ResetIteration()

	fmt.Printf("\n用户输入: %s\n", goal)

	// 显示跨会话历史信息
	// if len(e.crossSessionHistory) > 0 {
	// 	color.New(color.FgCyan).Printf("[记忆] 跨会话历史: %d 条消息，将作为对话历史添加\n", len(e.crossSessionHistory))
	// 	for i, msg := range e.crossSessionHistory {
	// 		roleSymbol := "👤"
	// 		if msg.Role == openai.ChatMessageRoleAssistant {
	// 			roleSymbol = "🤖"
	// 		}
	// 		content := msg.Content
	// 		if len(content) > 50 {
	// 			content = content[:50] + "..."
	// 		}
	// 		fmt.Printf("\t%d、 %s %s\n", i+1, roleSymbol, content)
	// 	}
	// }

	// ReAct主循环
	for e.agent.GetCurrentIteration() < e.agent.GetMaxIterations() {
		completed, err := e.processReActCycle(ctx, session)
		if err != nil {
			color.New(color.FgRed).Printf("[ERROR] %v\n", err)
			// 可以选择继续或停止，这里选择继续
			continue
		}

		// 当问题解决后，会话完成
		if completed {
			session.Complete()
			// 保存会话的真实对话历史
			e.saveSessionHistory(session)
			break
		}

		// 短暂延迟，避免API调用过于频繁
		time.Sleep(500 * time.Millisecond)
	}

	if e.agent.GetCurrentIteration() >= e.agent.GetMaxIterations() {
		session.Fail()
		// 即使失败也保存部分历史信息
		e.saveSessionHistory(session)
		fmt.Printf("\n[WARN] 达到最大循环次数 (%d 次)，会话结束\n", e.agent.GetMaxIterations())
	}

	return nil
}

// processReActCycle 处理一个ReAct循环
func (e *Engine) processReActCycle(ctx context.Context, session *ReActSession) (bool, error) {
	e.agent.IncrementIteration()

	//fmt.Printf("\n[循环] ReAct循环 %d/%d\n", e.agent.GetCurrentIteration(), e.agent.GetMaxIterations())

	// 构建消息（只在第一次循环时构建，按正确顺序添加）
	if e.agent.GetCurrentIteration() == 1 {
		// 1. 首先添加System消息
		systemPrompt, err := e.prompt.BuildSystemPrompt()
		if err != nil {
			return false, fmt.Errorf("构建系统提示失败: %v", err)
		}
		session.SetSystemMessage(systemPrompt)
		session.AddMessage(openai.ChatMessageRoleSystem, systemPrompt)

		// 2. 然后添加跨会话历史消息（如果有）
		if len(e.crossSessionHistory) > 0 {
			e.addCrossSessionHistory(session)
		}

		userMessage := session.Goal
		session.AddMessage(openai.ChatMessageRoleUser, userMessage)
	}

	// 使用引擎级的完整消息历史
	messages := e.getFullMessages(session)

	// 调用AI进行推理
	ctxTimeout, cancel := context.WithTimeout(ctx, time.Duration(e.agent.reasoningTimeout)*time.Second)
	defer cancel()

	resp, err := e.agent.GetClient().CreateChatCompletion(ctxTimeout, openai.ChatCompletionRequest{
		Model:    e.agent.GetModel(),
		Messages: messages,
	})

	if err != nil {
		return false, fmt.Errorf("AI推理失败: %v", err)
	}

	if len(resp.Choices) == 0 {
		return false, fmt.Errorf("AI无响应")
	}

	// 获取AI响应内容（但不立即添加到历史，等解析后根据类型决定）
	aiResponse := resp.Choices[0].Message.Content

	// 解析响应
	response, err := e.agent.ParseReActResponse(aiResponse)
	if err != nil {
		fmt.Printf("[DEBUG] AI响应内容: %s\n", truncateString(aiResponse, 500))
		return false, fmt.Errorf("解析AI响应失败: %v", err)
	}

	// 解析响应结构
	parsedResponse, err := e.prompt.ParseResponse(response)
	if err != nil {
		return false, fmt.Errorf("解析响应结构失败: %v", err)
	}

	// 根据响应类型处理
	switch parsedResponse.Type {
	case ResponseTypeThought:
		e.executeThought(session, parsedResponse.Content)
		return false, nil

	case ResponseTypeAction:
		err := e.executeAction(ctx, session, parsedResponse.Action, parsedResponse.Parameters)
		return false, err

	case ResponseTypeAskUser:
		err := e.executeAskUser(session, parsedResponse.Question)
		return false, err

	case ResponseTypeCompleted:
		e.executeCompleted(session, parsedResponse.Content, parsedResponse.FinalAnswer)
		return true, nil

	default:
		return false, fmt.Errorf("未知的响应类型: %s", parsedResponse.Type)
	}
}

// executeThought 处理思考步骤
func (e *Engine) executeThought(session *ReActSession, content string) {
	step := NewThoughtStep(content)
	step.ID = session.GetStepCount() + 1
	session.AddStep(step)

	color.New(color.FgCyan).Printf("\n[思考] %d: %s\n", step.ID, content)
}

// executeAction 处理行动步骤
func (e *Engine) executeAction(ctx context.Context, session *ReActSession, action string, parameters map[string]interface{}) error {
	step := NewActionStep(action, parameters)
	step.ID = session.GetStepCount() + 1

	color.New(color.FgCyan).Printf("\n[ACTION] %d: 使用 %s 工具，参数：%s\n", step.ID, action, step.GetParametersString())

	tool, exists := e.agent.GetTools()[action]
	if !exists {
		errorMsg := fmt.Sprintf("工具不存在: %s", action)
		step.SetError(fmt.Errorf("%s", errorMsg))
		session.AddStep(step)
		// 添加观察步骤记录错误
		observationStep := NewObservationStep(fmt.Sprintf("行动失败: %s", errorMsg))
		observationStep.ID = session.GetStepCount() + 1
		session.AddStep(observationStep)
		return fmt.Errorf("调用工具失败: %v", errorMsg)
	}

	// 执行工具
	output, err := tool.Execute(parameters)
	if err != nil {
		step.SetError(err)
		step.SetResult(fmt.Sprintf("Error: %v", err))
		session.AddStep(step)

		// 添加观察步骤记录错误
		observationStep := NewObservationStep(fmt.Sprintf("行动失败: %v", err))
		observationStep.ID = session.GetStepCount() + 1
		session.AddStep(observationStep)
		return fmt.Errorf("调用工具失败: %v", err)
	}

	step.SetResult(output)
	session.AddStep(step)

	// 添加观察步骤
	observationStep := NewObservationStep(output)
	observationStep.ID = session.GetStepCount() + 1
	session.AddStep(observationStep)

	color.New(color.FgCyan).Printf("[OK] 行动完成，结果: %s\n", truncateString(output, 200))
	return nil
}

// executeAskUser 处理询问用户步骤
func (e *Engine) executeAskUser(session *ReActSession, question string) error {
	step := NewAskUserStep(question)
	step.ID = session.GetStepCount() + 1
	session.AddStep(step)

	// 显示问题给用户
	color.New(color.FgYellow).Printf("\n[ASK] AI询问: %s\n", question)

	// 获取用户输入
	userAnswer, err := e.getUserInput()
	if err != nil {
		return fmt.Errorf("获取用户输入失败: %v", err)
	}

	// 创建用户回答步骤
	answerStep := NewUserAnswerStep(userAnswer)
	answerStep.ID = session.GetStepCount() + 1
	session.AddStep(answerStep)

	// 将用户回答添加到对话历史中，作为用户消息
	session.AddMessage(openai.ChatMessageRoleUser, userAnswer)

	color.New(color.FgGreen).Printf("[用户回答] %s\n", userAnswer)
	return nil
}

// getUserInput 获取用户输入
func (e *Engine) getUserInput() (string, error) {
	fmt.Print("请回答> ")
	reader := bufio.NewReader(os.Stdin)
	input, err := reader.ReadString('\n')
	if err != nil {
		return "", err
	}

	input = strings.TrimSpace(input)
	if input == "" {
		return "", fmt.Errorf("用户输入不能为空")
	}

	return input, nil
}

// executeCompleted 处理完成步骤
func (e *Engine) executeCompleted(session *ReActSession, content, finalAnswer string) {
	step := NewCompletedStep(content, finalAnswer)
	step.ID = session.GetStepCount() + 1
	session.AddStep(step)

	// 将最终答案添加到对话历史中，这是用户应该看到的助手回复
	session.AddMessage(openai.ChatMessageRoleAssistant, finalAnswer)

	color.New(color.FgCyan).Printf("\n[DONE] 任务完成: %s\n", content)
	color.New(color.FgGreen).Printf("\n助手回复: %s\n", finalAnswer)
}

// truncateString 截断字符串（按字节长度，注意UTF-8字符）
func truncateString(s string, maxLen int) string {
	if len(s) <= maxLen {
		return s
	}
	return s[:maxLen] + "..."
}
